﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using BigFileUploadDemo.Lib;
using System.IO;

namespace BigFileUploadDemo.Controllers
{
    public class FileController : Controller
    {
        private IWebHostEnvironment en;
        private readonly string _baseUploadDir;
        private RedisExchange redis = new RedisExchange();
        public FileController(IWebHostEnvironment en)
        {
            this.en = en;
            _baseUploadDir = string.Concat(en.WebRootPath, "\\upfile\\");
            if (!Directory.Exists(_baseUploadDir))
                Directory.CreateDirectory(_baseUploadDir);
        }
        public IActionResult Index()
        {
            return View();
        }
        /// <summary>
        /// 外部系统上传文件
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public IActionResult UploadApi()
        {
            Response resp = new Response();
            var data = Request.Form.Files[0];
            string md5 = Request.Form["md5"].ToString();
            var total = Request.Form["total"];
            var fileName = Request.Form["fileName"];
            var index = Request.Form["index"];
            var is_rewrite = Request.Form["rewrite"];
            string temporary = Path.Combine(_baseUploadDir, md5);//临时保存分块的目录
            if (redis.HashExists("upload_list", md5))
            {
                resp.code = 3;
                resp.message = "已上传";
                if (string.IsNullOrEmpty(is_rewrite) || is_rewrite.ToString() == "n")
                {
                    return Json(resp);
                }
                else if (!string.IsNullOrEmpty(is_rewrite) && is_rewrite.ToString() == "y")
                {
                    if (Directory.Exists(temporary))
                        Directory.Delete(temporary, true);
                    redis.HashDelete("upload_list", md5);
                }
            }
            try
            {
                bool mergeOk = false;
                if (!Directory.Exists(temporary))
                    Directory.CreateDirectory(temporary);

                string filePath = Path.Combine(temporary, index.ToString());
                //如果该文件上传过，且没有上传完成，执行如下续传逻辑
                //如果只有一个文件,直接删掉，如果大于一个文件，为了保证文件完整性，把最后一个文件删掉，再继续上传；
                if (index.ToString() == "0" && System.IO.File.Exists(filePath) && is_rewrite.ToString() != "y")
                {
                    resp.code = 2;
                    resp.message = $"{fileName}已上传，开始续传";
                    var files = Directory.GetFiles(temporary);
                    if (files.Length > 1)
                    {
                        //把标号最大的文件删掉；
                        string last_file = files.OrderByDescending(u => u.Length).ThenByDescending(u => u).First();
                        System.IO.File.Delete(last_file);
                        resp.data = new { index = files.Length - 2, total, mergeOk, fileName };
                    }
                    else
                        System.IO.File.Delete(filePath);
                    return Json(resp);
                }
                if (!Convert.IsDBNull(data))
                {
                    using (FileStream fs = new FileStream(filePath, FileMode.Create))
                    {
                        data.CopyTo(fs);
                    }
                }
                if (total == index)
                {
                    FIleLib fi = new FIleLib();
                    mergeOk = fi.MergeFileForClient(md5, fileName,_baseUploadDir);
                    if (mergeOk)
                        redis.HashSet("upload_list", md5, "success");
                }
                string url = $"/upfile/{DateTime.Now.ToString("yyyyMM")}/{md5}/{fileName}";
                resp.code = 1;
                resp.message = $"{index}/{total}上传完成";
                resp.data = new { index, total, mergeOk, fileName, url };
                return Json(resp);

            }
            catch (Exception ex)
            {
                Directory.Delete(temporary);//删除文件夹
                throw ex;
            }
        }

        /// <summary>
        /// web页面上传文件
        /// </summary>
        /// <param name="filename"></param>
        /// <returns></returns> 
        [HttpPost]
        public IActionResult UploadWeb()
        {
            Response resp = new Response();
            try
            {
                var fileName = Request.Form["file_name"];
                //当前分块序号
                var index = Convert.ToInt32(Request.Form["file_index"]);
                //所有块数
                var maxChunk = Convert.ToInt32(Request.Form["file_total"]);
                //前端传来的md5值
                var md5 = Request.Form["file_md5"];
                //临时保存分块的目录
                var dir = Path.Combine(_baseUploadDir, md5);
                if (!Directory.Exists(dir))
                    Directory.CreateDirectory(dir);
                //分块文件名为索引名，更严谨一些可以加上是否存在的判断，防止多线程时并发冲突
                var filePath = Path.Combine(dir, index.ToString());
                //表单中取得分块文件
                var file = Request.Form.Files["file_data"];
                //文件扩展名
                var suffix = Request.Form["file_suffix"];                
                //var filePathWithFileName = string.Concat(filePath, fileName);
                var filePathWithFileName = string.Concat(filePath, "." + suffix);
                using (var stream = new FileStream(filePathWithFileName, FileMode.Create))
                {
                    //file.CopyToAsync(stream);
                    file.CopyTo(stream);
                    LogicLog.WriteLogicLog(index.ToString(), _baseUploadDir + md5 + ".txt", false);
                }
                var uploadResponseModel = new RRModels.UploadResponseModel();
                uploadResponseModel.file_index = index;
                //如果是最后一个分块， 则合并文件
                if (index == maxChunk)
                {
                    FIleLib fi = new FIleLib();
                    uploadResponseModel = fi.MergeFileForWeb(fileName, md5,_baseUploadDir);
                    uploadResponseModel.Completed = true;                    
                }
                return Ok(uploadResponseModel);//直接返回符合前端数据结构的对象，和resp结构不同，偷个小懒；
            }
            catch(Exception ex)
            {
                resp.code = -1;
                resp.message = $"error:{ex.Message}";
            }
            return Json(resp);
        }

        /// <summary>
        /// 验证文件上传情况
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public IActionResult CheckFile()
        {
            Response resp = new Response();
            //前端传来的md5值
            var file_name = Request.Form["file_name"];
            var md5 = Request.Form["file_md5"];
            var maxChunk = Convert.ToInt32(Request.Form["file_total"]);
            string logPath = _baseUploadDir + md5 + ".txt";            
            var logs = LogicLog.ReadLogicLog(logPath);
            if (logs != null)
            {
                int shards = logs.Count();                
                if (shards >= Convert.ToInt32(maxChunk))
                {
                    resp.code = 2;
                    resp.message = "该文件已上传";
                    resp.data = new { url = $"/upfile/{DateTime.Now.ToString("yyyyMM")}/{md5}/{file_name}" };
                }
                else
                {
                    resp.code = 0;
                    resp.message = $"该文件已上传步长{shards}/{maxChunk}，继续上传";
                    resp.data = new { file_index = shards - 1, percent = Convert.ToDouble(shards) / Convert.ToDouble(maxChunk) * 100 };
                }
                //存在日志，文件却找不着了，说明被删了,注意排除掉临时文件夹的情况  
                string file_path = $"{_baseUploadDir}\\{DateTime.Now.ToString("yyyyMM")}\\{md5}\\{file_name}";
                string tmp_path = $"{_baseUploadDir}\\{md5}";
                if (!System.IO.Directory.Exists(tmp_path) && !System.IO.File.Exists(file_path) && System.IO.File.Exists(logPath))
                {
                    System.IO.File.Delete(logPath);
                    resp.code = 0;
                    resp.message = "该文件已被删除";
                    return Json(resp);
                }
            }
            return Json(resp);
        }

        /// <summary>
        /// 转化成pdf
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        [HttpGet]
        public IActionResult Convert2Pdf(string path)
        {
            Response resp = new Response();
            string complete_path = en.WebRootPath + path;
            if (System.IO.File.Exists(complete_path))
            {
                string suffix = System.IO.Path.GetExtension(complete_path);
                if ((suffix.Contains("doc") && Utils.AsposeUtils.WordToPDF(complete_path)) || (suffix.Contains("xls") && Utils.AsposeUtils.ExcelToPdf(complete_path)))
                {
                    resp.code = 1;
                    resp.message = "转换成功";
                    resp.data = new { url = path.Replace(suffix, ".pdf") };
                }
            }
            return Json(resp);
        }
    }
}
